﻿using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using Seagull.Configuration;
using Seagull.DAL;
using Seagull.DAL.Stat;
using Seagull.Model;
using Seagull.Model.Stat;
using Seagull.TestGeneric;
using Timer = System.Threading.Timer;

namespace Seagull.TestDataGen
{
    public partial class TestDataGenControlWindow : Form
    {
        private readonly Timer _liveDataTimer;
        private readonly object _syncRoot = new object();


        public TestDataGenControlWindow()
        {
            InitializeComponent();
            _liveDataTimer = new Timer(OnLiveDataTimerTick);
            _udpClient = new UdpClient();
        }

        private UdpClient _udpClient;

        void OnLiveDataTimerTick(object sender)
        {
            lock(_syncRoot)
            {
                try
                {
                    var timestamp = new DateTime(DateTime.Now.Ticks / 200000 * 200000);

                    // 每两秒发送相位数据
                    if(timestamp.Second % 2 == 0)
                    {
                        SendFrame(SourceDataHelper.GeneratePhaseData(timestamp.Second),
                            timestamp, FrameType.Phase, Channel.PhaseChannel);
                    }

                    // 发送帧数据
                    Config.Instance.ChannelConfig.ForAllChannels(channel =>
                    {
                        var frameType = FrameType.Data;
                        var frameData = SourceDataHelper.NextFrameData();
                        SendFrame(frameData, timestamp, frameType, channel);
                    });
                }
                catch(SocketException)
                {
                    return;
                }
            }
        }

        private void SendFrame(byte[] frameData, DateTime timestamp, FrameType frameType, byte channel)
        {
            var memoryStream = new MemoryStream(Frame.FrameSize);
            var writer = new BinaryWriter(memoryStream);
            writer.Write(Frame.Head);
            // TODO: diff frame types
            writer.Write((byte)frameType);
            writer.Write(channel);
            // Index
            writer.Write((byte)0);
            TimestampAccessor.Write(writer, timestamp);
            writer.Write((Int16)Frame.DataLength);
            writer.Write(frameData);
            writer.Write(0);
            writer.Write(Frame.Tail);

            _udpClient.Send(memoryStream.ToArray(), (int)memoryStream.Length);
        }

        private FileStream OpenHourFile(string fileName)
        {
            while(true)
            {
                try
                {
                    var fileInfo = new FileInfo(fileName);
                    PathHelper.EnsureDirectoryRecursively(fileInfo.Directory);
                    return File.Open(fileName, FileMode.Append, FileAccess.Write, FileShare.None);
                }
                catch(IOException e)
                {
                    Log(e.ToString());
                    Thread.Sleep(500);
                }
            }
        }

        private void Log(string msg)
        {
            this.BeginInvoke((Action)(() =>
                textBox1.Text += msg + Environment.NewLine));
        }

        private void StartGen(object sender, EventArgs e)
        {
            _udpClient.Connect("127.0.0.1", Config.Instance.PathConfig.RealTimePort);
            _liveDataTimer.Change(0, FrameSet.DefaultNormalFrameSpaceMilliseconds);
        }

        private void StopGen(object sender, EventArgs e)
        {
            _liveDataTimer.Change(-1, -1);
        }

        private void OnGenHistoryButtonClick(object sender, EventArgs e)
        {
            var date = DateTime.Today.AddDays(-1);
            for(byte channel = 1; channel < 2; channel++)
            {
                for(int hour = 0; hour < 6; hour++)
                {
                    var segment = new Segment(channel, date, hour);
                    SourceDataHelper.GenDataForSegment(segment);
                }
            }
            MessageBox.Show(string.Format("{0}通道1 0:00 - 5:00数据已生成", date.ToShortDateString()));
        }

        private void OnGenStatButtonClick(object sender, EventArgs e)
        {
            // 生成过去一个月的统计数据
            var random = new Random();
            Func<Statistic> newStat = () => new Statistic(
                (byte)random.Next(130, 250), (byte)random.Next(100, 150));
            for(byte channel = 1; channel <= 3; channel++)
            {
                var channelStatFile = PathHelper.GetChannelStatFile(channel);
                if(channelStatFile.Exists)
                {
                    channelStatFile.Delete();
                }
                var channelStatFileWriter = new ChannelStatFileWriter(channel);
                var time = DateTime.Today.AddDays(-10);
                while(time < DateTime.Today)
                {
                    channelStatFileWriter.Append(new TimeStatistic(time, newStat()));
                    var pathHelper = new PathHelper(Config.Instance.PathConfig.StatFolder, Config.Instance.PathConfig.StatFileExtension);
                    var statFileWriter = new FrameStatFileWriter(
                        OpenHourFile(pathHelper.GetSegmentFile(new Segment(channel, time)).FullName));
                    using(statFileWriter)
                    {
                        for(int i = 0; i < Segment.FrameCount; i++)
                        {
                            statFileWriter.Write(newStat());
                        }
                    }
                    time = time.AddHours(1);
                }
            }
            MessageBox.Show(string.Format("通道1-3 过去10天统计数据已生成"));
        }
    }
}
